/*
 * Copyright (c) 2025 Huawei Device, Inc. Ltd. and <马弓手>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "AudioHandler.h"
#include "cJSON.h"
#include "file/FileUtils.h"
#include "media/AudioPlayer.h"

REGISTER_PLUGIN_CLASS(AudioHandler)
bool AudioHandler::execute(const string&  action, cJSON* args, CallbackContext cbc)
{
    if(action == "startRecordingAudio") {
        if(cJSON_GetArraySize(args) < 2) {
            return false;
        }
        string strId = cJSON_GetArrayItem(args, 0)->valuestring;
        string strTarget = cJSON_GetArrayItem(args, 1)->valuestring;
        strTarget = CFilesystem::getNativeUrl(strTarget);
        
        if(m_mapIdToAudioPlayer.find(strId) != m_mapIdToAudioPlayer.end()) {
            AudioPlayer* pPlayer = (AudioPlayer*)m_mapIdToAudioPlayer[strId];
            pPlayer->reset();
            pPlayer->release();
            m_mapIdToAudioPlayer.erase(strId);
        }
        
        cJSON* pJson = cJSON_CreateObject();
        cJSON_AddStringToObject(pJson, "id", strId.c_str());
        cJSON_AddStringToObject(pJson, "target", strTarget.c_str());
        char *pStrJson = cJSON_Print(pJson);
        executeArkTs("./MediaAction/AudioRecorder/StartRecordingAudio", 0, pStrJson, "Media", cbc);
        free(pStrJson);
        cJSON_Delete(pJson);
        m_isPlaying = false;
    } else if(action == "stopRecordingAudio") {
        if(cJSON_GetArraySize(args) < 1) {
            return false;
        }
        string strId = cJSON_GetArrayItem(args, 0)->valuestring;
        executeArkTs("./MediaAction/AudioRecorder/StopRecordingAudio", 0, strId.c_str(), "Media", cbc);
        m_isPlaying = true;
    } else if(action == "pauseRecordingAudio") {
        if(cJSON_GetArraySize(args) < 1) {
            return false;
        }
        string strId = cJSON_GetArrayItem(args, 0)->valuestring;
        executeArkTs("./MediaAction/AudioRecorder/PauseRecordingAudio", 0, strId.c_str(), "Media", cbc);
    } else if(action == "resumeRecordingAudio") {
        if(cJSON_GetArraySize(args) < 1) {
            return false;
        }
        string strId = cJSON_GetArrayItem(args, 0)->valuestring;
        executeArkTs("./MediaAction/AudioRecorder/ResumeRecordingAudio", 0, strId.c_str(), "Media", cbc);
    } else if(action == "startPlayingAudio" && m_isPlaying) {
        if(cJSON_GetArraySize(args) < 2) {
            return false;
        }
        string strId = cJSON_GetArrayItem(args, 0)->valuestring;
        string strTarget = cJSON_GetArrayItem(args, 1)->valuestring;
        strTarget = CFilesystem::getNativeUrl(strTarget);
        AudioPlayer* pPlayer = nullptr;
        if(m_mapIdToAudioPlayer.find(strId) == m_mapIdToAudioPlayer.end()) {
            pPlayer = new AudioPlayer(this, strId);
            m_mapIdToAudioPlayer[strId] = pPlayer;
        } else {
            pPlayer = (AudioPlayer*)m_mapIdToAudioPlayer[strId];
        }
        if(pPlayer->getState() == AudioPlayer::RELEASED) {
            if(!pPlayer->create()) {
                return false;
            } else if(!pPlayer->setSource(strTarget)) {
                return false;
            } else if(!pPlayer->prepare()) {
                return false;
            } else if(!pPlayer->play()) {
                return false;
            }
        } else if(pPlayer->getState() == AudioPlayer::COMPLETED || pPlayer->getState() == AudioPlayer::STOPPED) {
            if(!pPlayer->reset()) {
                return false;
            } else if(!pPlayer->setSource(strTarget)) {
                return false;
            } else if(!pPlayer->prepare()) {
                return false;
            } else if(!pPlayer->play()) {
                return false;
            }
        } else if(pPlayer->getState() == AudioPlayer::PAUSED || pPlayer->getState() == AudioPlayer::PREPARED) {
            if(!pPlayer->play()) {
                return false;
            }
        }
    } else if(action == "seekToAudio" && m_isPlaying) {
        if(cJSON_GetArraySize(args) < 2) {
            return false;
        }
        string strId = cJSON_GetArrayItem(args, 0)->valuestring;
        long lngMSec = cJSON_GetArrayItem(args, 1)->valuedouble;
        if(m_mapIdToAudioPlayer.find(strId) != m_mapIdToAudioPlayer.end()) {
            AudioPlayer* pPlayer = (AudioPlayer*)m_mapIdToAudioPlayer[strId];
            pPlayer->seekTo(lngMSec);
        }
    } else if(action == "pausePlayingAudio" && m_isPlaying) {
        if(cJSON_GetArraySize(args) < 1) {
            return false;
        }
        string strId = cJSON_GetArrayItem(args, 0)->valuestring;
        if(m_mapIdToAudioPlayer.find(strId) != m_mapIdToAudioPlayer.end()) {
            AudioPlayer* pPlayer = (AudioPlayer*)m_mapIdToAudioPlayer[strId];
            pPlayer->pause();
        }
    } else if(action == "stopPlayingAudio" && m_isPlaying) {
        if(cJSON_GetArraySize(args) < 1) {
            return false;
        }
        string strId = cJSON_GetArrayItem(args, 0)->valuestring;
        if(m_mapIdToAudioPlayer.find(strId) != m_mapIdToAudioPlayer.end()) {
            AudioPlayer* pPlayer = (AudioPlayer*)m_mapIdToAudioPlayer[strId];
            pPlayer->stop();
        }
    } else if(action == "setVolume" && m_isPlaying) {
        if(cJSON_GetArraySize(args) < 2) {
            return false;
        }
        string strId = cJSON_GetArrayItem(args, 0)->valuestring;
        float fVolume = cJSON_GetArrayItem(args, 1)->valuedouble;
        if(m_mapIdToAudioPlayer.find(strId) != m_mapIdToAudioPlayer.end()) {
            AudioPlayer* pPlayer = (AudioPlayer*)m_mapIdToAudioPlayer[strId];
            pPlayer->setVolume(fVolume);
        }
    } else if(action == "getCurrentPositionAudio" && m_isPlaying) {
        if(cJSON_GetArraySize(args) < 1) {
            return false;
        }
        int nPosition = 0;
        string strId = cJSON_GetArrayItem(args, 0)->valuestring;
        if(m_mapIdToAudioPlayer.find(strId) != m_mapIdToAudioPlayer.end()) {
            AudioPlayer* pPlayer = (AudioPlayer*)m_mapIdToAudioPlayer[strId];
            pPlayer->getCurrentPosition(nPosition);
        }
        PluginResult pluginResult(PluginResult::OK, nPosition/1000);
        cbc.sendPluginResult(pluginResult);
        return true;
    } else if(action == "getDurationAudio" && m_isPlaying) {
        if(cJSON_GetArraySize(args) < 1) {
            return false;
        }
        int nDuration = 0;
        string strId = cJSON_GetArrayItem(args, 0)->valuestring;
        if(m_mapIdToAudioPlayer.find(strId) != m_mapIdToAudioPlayer.end()) {
            AudioPlayer* pPlayer = (AudioPlayer*)m_mapIdToAudioPlayer[strId];
            pPlayer->getDuration(nDuration);
        }
        PluginResult pluginResult(PluginResult::OK, nDuration);
        cbc.sendPluginResult(pluginResult);
        return true;
    } else if(action == "create") {
        if(cJSON_GetArraySize(args) < 2) {
            return false;
        }
        string strId = cJSON_GetArrayItem(args, 0)->valuestring;
        string strTarget = cJSON_GetArrayItem(args, 1)->valuestring;
        strTarget = CFilesystem::getNativeUrl(strTarget);
        if(m_mapIdToAudioPlayer.find(strId) == m_mapIdToAudioPlayer.end()) {
            AudioPlayer* pPlayer = new AudioPlayer(this, strId);
            m_mapIdToAudioPlayer[strId] = pPlayer;
            //文件存在先取出播放长度
            if(pPlayer->create()) {
                if(pPlayer->setSource(strTarget)) {
                    pPlayer->prepare();
                }
            }
        }
    } else if(action == "release") {
        if(cJSON_GetArraySize(args) < 1) {
            return false;
        }
        bool isOk = false;
        string strId = cJSON_GetArrayItem(args, 0)->valuestring;
        if(m_mapIdToAudioPlayer.find(strId) != m_mapIdToAudioPlayer.end()) {
            AudioPlayer* pPlayer = (AudioPlayer*)m_mapIdToAudioPlayer[strId];
            pPlayer->release();
            delete pPlayer;
            m_mapIdToAudioPlayer.erase(strId);
            isOk = true;
        }
        PluginResult pluginResult(PluginResult::OK, isOk);
        cbc.sendPluginResult(pluginResult);
        return true;
    } else if(action == "messageChannel") {
        m_cbc = cbc;
        return true;
    } else if(action == "getCurrentAmplitudeAudio") {
        PluginResult pluginResult(PluginResult::OK, 0);
        cbc.sendPluginResult(pluginResult);
        return true;
    } else if(action == "setRate" && m_isPlaying) {
        if(cJSON_GetArraySize(args) < 2) {
            return false;
        }
        string strId = cJSON_GetArrayItem(args, 0)->valuestring;
        float fRate = cJSON_GetArrayItem(args, 1)->valuedouble;
        if(m_mapIdToAudioPlayer.find(strId) != m_mapIdToAudioPlayer.end()) {
            AudioPlayer* pPlayer = (AudioPlayer*)m_mapIdToAudioPlayer[strId];
            pPlayer->setPlaybackSpeed(fRate);
        }
    } else {
        return false;
    }
    PluginResult pluginResult(PluginResult::OK, "");
    cbc.sendPluginResult(pluginResult);
    return true;
}

void AudioHandler::sendEventMessage(string strAction, cJSON* pJsonActionData) {
    cJSON* pMessage = cJSON_CreateObject();
    cJSON_AddStringToObject(pMessage, "action", strAction.c_str());
    if(pJsonActionData != NULL) {
        cJSON_AddItemToObject(pMessage, strAction.c_str(), pJsonActionData);
    }
    PluginResult pluginResult(PluginResult::OK, pMessage);
    pluginResult.setKeepCallback(true);
    if(m_cbc.getQueue() != nullptr) {
        m_cbc.sendPluginResult(pluginResult);
    }
    cJSON_Delete(pMessage);
}